home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 3.iso / dist / fw_qt3.idb / usr / freeware / Qt / examples / demo / graph.cpp.z / graph.cpp
C/C++ Source or Header  |  2002-04-08  |  10KB  |  444 lines

  1. #include "graph.h"
  2. #include <qcanvas.h>
  3. #include <stdlib.h>
  4. #include <qdatetime.h>
  5. #include <qhbox.h>
  6. #include <qpushbutton.h>
  7. #include <qslider.h>
  8. #include <qlabel.h>
  9. #include <qlayout.h>
  10.  
  11. const int bounce_rtti = 1234;
  12.  
  13. // We use a global variable to save memory - all the brushes and pens in
  14. // the mesh are shared.
  15. static QBrush *tb = 0;
  16. static QPen *tp = 0;
  17.  
  18. class EdgeItem;
  19. class NodeItem;
  20. class FigureEditor;
  21. typedef QValueList<NodeItem*> NodeItemList;
  22. typedef QValueList<EdgeItem*> EdgeItemList;
  23.  
  24. #define SPEED2ADVANCE(x) (301-x)
  25.  
  26. class GraphWidgetPrivate
  27. {
  28. public:
  29.     GraphWidgetPrivate() {
  30.     moving = 0;
  31.     speed = 200;
  32.     }
  33.     ~GraphWidgetPrivate() {
  34.     delete canvas;
  35.     }
  36.     NodeItemList nodeItems;
  37.     FigureEditor* editor;
  38.     QCanvas* canvas;
  39.     QCanvasItem* moving;
  40.     int speed;
  41. };
  42.  
  43. class EdgeItem: public QCanvasLine
  44. {
  45. public:
  46.     EdgeItem( NodeItem*, NodeItem*, QCanvas* );
  47.     void setFromPoint( int x, int y ) ;
  48.     void setToPoint( int x, int y );
  49.     void moveBy(double dx, double dy);
  50.  
  51.     NodeItem* from;
  52.     NodeItem* to;
  53. };
  54.  
  55.  
  56.  
  57. class NodeItem: public QCanvasEllipse
  58. {
  59. public:
  60.     NodeItem( GraphWidgetPrivate* g );
  61.     ~NodeItem() {}
  62.  
  63.     void addInEdge( EdgeItem *edge ) { inList.append( edge ); }
  64.     void addOutEdge( EdgeItem *edge ) { outList.append( edge ); }
  65.  
  66.     void moveBy(double dx, double dy);
  67.  
  68.     void calcForce();
  69.     void advance( int stage );
  70.  
  71. private:
  72.     GraphWidgetPrivate* graph;
  73.     EdgeItemList inList;
  74.     EdgeItemList outList;
  75. };
  76.  
  77.  
  78.  
  79. void EdgeItem::moveBy(double, double)
  80. {
  81.     //nothing
  82. }
  83.  
  84. EdgeItem::EdgeItem( NodeItem *fromItem, NodeItem *toItem, QCanvas *canvas )
  85.     : QCanvasLine( canvas )
  86. {
  87.     from = fromItem;
  88.     to = toItem;
  89.     setPen( *tp );
  90.     setBrush( *tb );
  91.     from->addOutEdge( this );
  92.     to->addInEdge( this );
  93.     setPoints( int(from->x()), int(from->y()), int(to->x()), int(to->y()) );
  94.     setZ( 127 );
  95. }
  96.  
  97. void EdgeItem::setFromPoint( int x, int y )
  98. {
  99.     setPoints( x,y, endPoint().x(), endPoint().y() );
  100. }
  101.  
  102. void EdgeItem::setToPoint( int x, int y )
  103. {
  104.     setPoints( startPoint().x(), startPoint().y(), x, y );
  105. }
  106.  
  107.  
  108. void NodeItem::moveBy(double dx, double dy)
  109. {
  110.     double nx = x() + dx;
  111.     double ny = y() + dy;
  112.     if ( graph->moving != this ) {
  113.     nx = QMAX( width()/2, nx );
  114.     ny = QMAX( height()/2, ny );
  115.     nx = QMIN( canvas()->width() - width()/2, nx );
  116.     ny = QMIN( canvas()->height() - height()/2, ny );
  117.     }
  118.     QCanvasEllipse::moveBy( nx-x(), ny-y() );
  119.     EdgeItemList::Iterator it;
  120.     for (  it = inList.begin(); it != inList.end(); ++it )
  121.     (*it)->setToPoint( int(x()), int(y()) );
  122.     for (  it = outList.begin(); it != outList.end(); ++it )
  123.     (*it)->setFromPoint( int(x()), int(y()) );
  124. }
  125.  
  126. NodeItem::NodeItem( GraphWidgetPrivate* g )
  127.     : QCanvasEllipse( 32, 32, g->canvas )
  128. {
  129.     graph = g;
  130.     graph->nodeItems.append( this );
  131.     setPen( *tp );
  132.     setBrush( *tb );
  133.     setZ( 128 );
  134. }
  135.  
  136. void NodeItem::advance( int stage ) {
  137.     switch ( stage ) {
  138.     case 0:
  139.         calcForce();
  140.         break;
  141.     case 1:
  142.         QCanvasItem::advance(stage);
  143.         break;
  144.     }
  145. }
  146.  
  147. void NodeItem::calcForce() {
  148.     if ( graph->moving == this ) {
  149.     setVelocity( 0, 0 );
  150.     return;
  151.     }
  152.     double xvel = 0;
  153.     double yvel = 0;
  154.     for ( NodeItemList::Iterator it = graph->nodeItems.begin(); it != graph->nodeItems.end(); ++it ) {
  155.     NodeItem* n = (*it);
  156.     if ( n == this )
  157.         continue;
  158.     double dx  = x() - n->x();
  159.     double dy  = y() - n->y();
  160.     double l = 2 * ( dx * dx + dy * dy );
  161.     if ( l > 0 ) {
  162.         xvel = xvel + dx*260 / l;
  163.         yvel = yvel + dy*260 / l;
  164.     }
  165.     }
  166.     double w = 1 + outList.count() + inList.count();
  167.     w *= 10;
  168.     EdgeItemList::Iterator it2;
  169.     EdgeItem * e;
  170.     NodeItem* n;
  171.     for ( it2 = outList.begin(); it2 != outList.end(); ++it2 ) {
  172.     e = (*it2);
  173.     n = e->to;
  174.     xvel = xvel - ( x() - n->x() ) / w;
  175.     yvel = yvel - ( y() - n->y() ) / w;
  176.     }
  177.     for ( it2 = inList.begin(); it2 != inList.end(); ++it2 ) {
  178.     e = (*it2);
  179.     n = e->from;
  180.     xvel = xvel - ( x() - n->x() ) / w;
  181.     yvel = yvel - ( y() - n->y() ) / w;
  182.     }
  183.     if ( QABS( xvel ) < .1 && QABS( yvel ) < .1 )
  184.     xvel = yvel = 0;
  185.    setVelocity( xvel, yvel );
  186. }
  187.  
  188.  
  189. class FigureEditor : public QCanvasView {
  190. public:
  191.     FigureEditor( GraphWidgetPrivate *g, QWidget* parent=0, const char* name=0, WFlags f=0);
  192.  
  193.     QSize sizeHint() const;
  194.  
  195.  
  196. protected:
  197.     void contentsMousePressEvent(QMouseEvent*);
  198.     void contentsMouseReleaseEvent(QMouseEvent*);
  199.     void contentsMouseMoveEvent(QMouseEvent*);
  200.  
  201.  
  202.     void resizeEvent( QResizeEvent* );
  203.     void showEvent( QShowEvent* );
  204.     void hideEvent( QHideEvent* e);
  205.  
  206. private:
  207.     void initialize();
  208.     QPoint moving_start;
  209.     GraphWidgetPrivate* graph;
  210. };
  211.  
  212.  
  213. FigureEditor::FigureEditor(
  214.     GraphWidgetPrivate* g, QWidget* parent,
  215.     const char* name, WFlags f) :
  216.     QCanvasView(g->canvas, parent,name,f)
  217. {
  218.     graph = g;
  219. }
  220.  
  221. void FigureEditor::contentsMousePressEvent(QMouseEvent* e)
  222. {
  223.     QCanvasItemList l=canvas()->collisions(e->pos());
  224.     for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
  225.     if ((*it)->rtti()==bounce_rtti )
  226.         continue;
  227.     graph->moving = *it;
  228.     moving_start = e->pos();
  229.     return;
  230.     }
  231.     graph->moving = 0;
  232. }
  233.  
  234. void FigureEditor::contentsMouseReleaseEvent(QMouseEvent* )
  235. {
  236.     if ( graph->moving )
  237.     graph->moving = 0;
  238. }
  239.  
  240. void FigureEditor::contentsMouseMoveEvent(QMouseEvent* e)
  241. {
  242.     if ( graph->moving ) {
  243.     graph->moving->moveBy(e->pos().x() - moving_start.x(),
  244.                e->pos().y() - moving_start.y());
  245.     moving_start = e->pos();
  246.     canvas()->update();
  247.     }
  248. }
  249.  
  250. class BouncyText : public QCanvasText {
  251.     void initPos();
  252.     void initSpeed();
  253. public:
  254.     int rtti() const;
  255.     BouncyText(const QString&, QFont, QCanvas*);
  256.     void advance(int);
  257. };
  258.  
  259. BouncyText::BouncyText( const QString& text, QFont f, QCanvas* canvas) :
  260.     QCanvasText(text, f, canvas)
  261. {
  262.     setAnimated(TRUE);
  263.     initPos();
  264. }
  265.  
  266.  
  267. int BouncyText::rtti() const
  268. {
  269.     return bounce_rtti;
  270. }
  271.  
  272. void BouncyText::initPos()
  273. {
  274.     initSpeed();
  275.     int trial=1000;
  276.     do {
  277.     move(rand()%(canvas()->width()-boundingRect().width()),
  278.          rand()%(canvas()->height()-boundingRect().height()));
  279.     advance(0);
  280.     } while (trial-- && xVelocity()==0.0 && yVelocity()==0.0);
  281. }
  282.  
  283. void BouncyText::initSpeed()
  284. {
  285.     const double speed = 2.0;
  286.     double d = (double)(rand()%1024) / 1024.0;
  287.     double e = (double)(rand()%1024) / 1024.0;
  288.  
  289.     if ( d < .5 )
  290.     d = -1 - d;
  291.     else
  292.     d = d + 1;
  293.     if ( e < .5 )
  294.     e = -1 - e;
  295.     else
  296.     e = e + 1;
  297.  
  298.     setVelocity( d*speed, e * speed );
  299. }
  300.  
  301. void BouncyText::advance( int stage )
  302. {
  303.     switch ( stage ) {
  304.       case 0: {
  305.     double vx = xVelocity();
  306.     double vy = yVelocity();
  307.  
  308.     if ( vx == 0.0 && vy == 0.0 ) {
  309.         // stopped last turn
  310.         initSpeed();
  311.         vx = xVelocity();
  312.         vy = yVelocity();
  313.     }
  314.  
  315.     QRect r = boundingRect();
  316.     r.moveBy( int(vx), int(vy) );
  317.  
  318.     if ( r.left() < 0 || r.right() > canvas()->width() )
  319.         vx = -vx;
  320.     if ( r.top() < 0 || r.bottom() > canvas()->height() )
  321.         vy = -vy;
  322.  
  323.     r = boundingRect();
  324.     r.moveBy( int(vx), int(vy) );
  325.     if ( r.left() < 0 || r.right() > canvas()->width() )
  326.         vx = 0;
  327.     if ( r.top() < 0 || r.bottom() > canvas()->height() )
  328.         vy = 0;
  329.  
  330.     setVelocity( vx, vy );
  331.       } break;
  332.       case 1:
  333.     QCanvasItem::advance( stage );
  334.     break;
  335.     }
  336. }
  337.  
  338. GraphWidget::GraphWidget( QWidget *parent, const char *name)
  339.     : QWidget( parent, name )
  340. {
  341.     d = new GraphWidgetPrivate;
  342.     d->canvas = 0;
  343.     QVBoxLayout* vb = new QVBoxLayout(  this, 11, 6 );
  344.     d->editor = new FigureEditor( d, this  );
  345.     vb->addWidget( d->editor );
  346.     QHBoxLayout* hb = new QHBoxLayout(  vb );
  347.     hb->addWidget( new QLabel("Slow", this ) );
  348.     QSlider* slider = new QSlider( 0, 300, 25, d->speed, Horizontal, this );
  349.     connect( slider, SIGNAL( valueChanged(int) ), this, SLOT( setSpeed(int) ) );
  350.     hb->addWidget( slider );
  351.     hb->addWidget( new QLabel("Fast", this ) );
  352.     hb->addSpacing( 10 );
  353.     QPushButton* btn = new QPushButton( "Shuffle Nodes", this );
  354.     connect( btn, SIGNAL( clicked() ), this, SLOT( shuffle() ) );
  355.     hb->addWidget( btn );
  356. }
  357.  
  358.  
  359. GraphWidget::~GraphWidget()
  360. {
  361.     delete d;
  362. }
  363.  
  364. void GraphWidget::setSpeed(int s)
  365. {
  366.     d->speed = s;
  367.     if ( isVisible() && d->canvas )
  368.     d->canvas->setAdvancePeriod( SPEED2ADVANCE( s ) );
  369. }
  370.  
  371. void GraphWidget::shuffle()
  372. {
  373.  
  374.     for ( NodeItemList::Iterator it = d->nodeItems.begin(); it != d->nodeItems.end(); ++it ) {
  375.     NodeItem* ni = (*it);
  376.     ni->move(rand()%(d->canvas->width()-ni->width()),rand()%(d->canvas->height()-ni->height()));
  377.     }
  378. }
  379.  
  380.  
  381. QSize FigureEditor::sizeHint() const
  382. {
  383.     return QSize( 600, 400 );
  384. }
  385.  
  386. void FigureEditor::resizeEvent( QResizeEvent* e )
  387. {
  388.     if ( canvas() )
  389.     canvas()->resize( QMAX( 590, contentsRect().width()), QMAX(390, contentsRect().height() ));
  390.     QCanvasView::resizeEvent( e );
  391. }
  392.  
  393. void FigureEditor::showEvent( QShowEvent* )
  394. {
  395.     initialize();
  396.     canvas()->setAdvancePeriod( SPEED2ADVANCE(graph->speed) );
  397. }
  398.  
  399. void FigureEditor::hideEvent( QHideEvent* )
  400. {
  401.     initialize();
  402.     canvas()->setAdvancePeriod( -10 );
  403. }
  404.  
  405. void FigureEditor::initialize()
  406. {
  407.     if ( canvas() )
  408.     return;
  409.     resize( sizeHint() );
  410.     graph->canvas = new QCanvas( contentsRect().width(), contentsRect().height() );
  411.     if ( !tb ) tb = new QBrush( Qt::red );
  412.     if ( !tp ) tp = new QPen( Qt::black );
  413.     srand( QTime::currentTime().msec() );
  414.     int nodecount = 0;
  415.  
  416.     int rows = 3;
  417.     int cols = 3;
  418.  
  419.     QMemArray<NodeItem*> lastRow(cols);
  420.     for ( int r = 0; r < rows; r++ ) {
  421.     NodeItem *prev = 0;
  422.     for ( int c = 0; c < cols; c++ ) {
  423.         NodeItem *ni = new NodeItem( graph );
  424.         ni->setAnimated( TRUE );
  425.         nodecount++;
  426.         ni->move(rand()%(graph->canvas->width()-ni->width()),rand()%(graph->canvas->height()-ni->height()));
  427.  
  428.         if ( r > 0 )
  429.         (new EdgeItem( lastRow[c], ni, graph->canvas ))->show();
  430.         if ( prev )
  431.         (new EdgeItem( prev, ni, graph->canvas ))->show();
  432.         prev = ni;
  433.         lastRow[c] = ni;
  434.         ni->show();
  435.     }
  436.     }
  437.  
  438.     graph->canvas->advance();
  439.  
  440.     QCanvasItem* i = new BouncyText( "Drag the nodes around!", QFont("helvetica", 24), graph->canvas);
  441.     i->show();
  442.     setCanvas( graph->canvas );
  443. }
  444.